package com.lurenjia.pets_adoption.controller;

import cn.hutool.core.util.StrUtil;
import com.lurenjia.pets_adoption.dto.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 文件上传下载控制器
 * <p>
 * 提供文件上传和下载功能，主要用于宠物图片的管理。支持文件上传至服务器指定目录，
 * 以及从服务器下载文件。使用Redis作为缓存提高文件读取效率。
 *
 * @module 图片上传下载
 */
@RestController
@RequestMapping("/common")
@EnableCaching
@Slf4j
public class FileDownUpController {

    @Value("${pets_adoption.file-path}")
    private String imagePath;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 文件下载接口
     * <p>
     * 根据文件名从服务器指定目录读取文件，并将文件内容通过HTTP响应流返回给客户端。
     * 支持图片等文件的下载，并使用Redis缓存机制提高访问效率。
     *
     * @param name     要下载的文件名
     * @param response HTTP响应对象，用于将文件内容写入响应流
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) {
        try {
            //获取响应流
            ServletOutputStream outputStream = response.getOutputStream();
            //读取图片到字节数组中
            byte[] image = getImageFileBytes(name);
            //图片字节数据写入响应流中
            outputStream.write(image);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过文件名获取文件的字节数组
     * <p>
     * 首先尝试从Redis缓存中获取文件内容，如果缓存中不存在则从文件系统中读取文件，
     * 并将读取到的文件内容存入Redis缓存5分钟。
     *
     * @param name 文件名
     * @return 文件的字节数组
     * @throws IOException 文件读取异常
     */
    private byte[] getImageFileBytes(String name) throws IOException {
        //缓存中没有

        //从缓存中拿
        String value = redisTemplate.opsForValue().get("pet:image:"+name);
        if(StrUtil.isNotBlank(value)){
            byte[] resp = value.getBytes();
        }

        // 修复路径拼接问题，确保使用正确的文件分隔符
        File imageFile = new File(imagePath, name);
        byte[] image = FileUtils.readFileToByteArray(imageFile);
        log.info("从文件中拿到文件：{}",name);
        //放入缓存中
        redisTemplate.opsForValue().set("pet:image:"+name, Arrays.toString(image),5L, TimeUnit.MINUTES);
        return image;
    }

    /**
     * 文件上传接口
     * <p>
     * 接收客户端上传的文件，为文件生成唯一标识符并保存到服务器指定目录中。
     * 支持多种格式文件上传，主要用于宠物图片上传。
     *
     * @param file 客户端上传的文件对象
     * @return 包含新生成文件名的响应结果
     */
    @PostMapping("/upload")
    public R<String> upLoad(MultipartFile file) {
        //获取原始文件名
        String fileName = file.getOriginalFilename();
        //获取到扩展名
        String suffix = fileName.substring(fileName.lastIndexOf("."));

        //生成唯一文件名
        String realFileName = UUID.randomUUID().toString() + suffix;

        //获取到配置文件中的文件储存地址，判断文件夹是否存在
        File dir = new File(imagePath);
        if (!dir.exists()) {
            //文件夹不存在则新建，使用 mkdirs 确保创建所有必要的父目录
            dir.mkdirs();
            log.info("新建文件夹：{}", imagePath);
        }

        //文件保存到指定目录下
        try {
            log.info("文件开始保存:{}", realFileName);
            // 修复路径拼接问题，使用 File 构造函数确保正确的路径分隔符
            File destFile = new File(dir, realFileName);
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //把文件名响应和客户端
        return R.success(realFileName);
    }
}
